home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / share / ghostscript / 8.64 / Resource / Init / pdf_sec.ps < prev    next >
Encoding:
Text File  |  2009-04-17  |  15.2 KB  |  526 lines

  1. % Copyright (C) 1996-1998 Geoffrey Keating.
  2. % Copyright (C) 2001-2008 Artifex Software, Inc.
  3. % This file may be freely distributed with or without modifications,
  4. % so long as modified versions are marked as such and copyright notices are
  5. % not removed.
  6.  
  7. % $Id: pdf_sec.ps 9232 2008-11-20 19:31:36Z giles $
  8. % Implementation of security hooks for PDF reader.
  9.  
  10. % This file contains the procedures that have to take encryption into
  11. % account when reading a PDF file. It was originally distributed
  12. % separately by Geoffrey Keating as an add-on to version 6 and earlier.
  13.  
  14. % Modified by Alex Cherepanov to work with GS 6.60 and higher.
  15. % New versions of GS require explicit checks for /true, /false, and /null
  16. % in .decpdfrun. This fix is backward-compatible.
  17.  
  18. % Modified by Raph Levien and Ralph Giles to use the new C 
  19. % implementations of md5 and arcfour in ghostscript 7.01, and to 
  20. % be compatible with PDF 1.4 128-bit encryption.
  21.  
  22. % Modified by Ralph Giles for PDF 1.6 AES encryption.
  23.  
  24. /.setlanguagelevel where { pop 2 .setlanguagelevel } if
  25. .currentglobal true .setglobal
  26. /pdfdict where { pop } { /pdfdict 100 dict def } ifelse
  27. pdfdict begin
  28.  
  29. % Older ghostscript versions do not have .pdftoken, so we use 'token' instead.
  30. /.pdftoken where { pop } { /.pdftoken /token load def } ifelse
  31.  
  32. % take a stream and arc4 decrypt it.
  33. % <stream> <key> arc4decodefilter <stream>
  34. /arc4decodefilter {
  35.   1 dict begin
  36.   /Key exch def
  37.   currentdict end /ArcfourDecode filter
  38. } bind def
  39.  
  40. % <ciphertext> <key> arc4decode <plaintext>
  41. /arc4decode {
  42.   1 index length 0 eq {
  43.     pop
  44.   } {
  45.     1 index length string 3 1 roll arc4decodefilter exch readstring pop
  46.   } ifelse
  47. } bind def
  48.  
  49. % take a stream and aes decrypt it.
  50. % <stream> <key> aesdecodefilter <stream>
  51. /aesdecodefilter {
  52.   1 dict begin
  53.   /Key exch def
  54.   currentdict end
  55.   /AESDecode filter
  56. } bind def
  57.  
  58. % <ciphertext> <key> aesdecode <plaintext>
  59. /aesdecode {
  60.   1 index length 0 eq {
  61.     pop
  62.   } {
  63.     1 index length string 3 1 roll
  64.     aesdecodefilter exch readstring pop
  65.   } ifelse
  66. } bind def
  67.  
  68. /md5 {
  69.   16 string dup /MD5Encode filter dup 4 3 roll writestring closefile
  70. } bind def
  71.  
  72. /md5_trunk {
  73.   md5 0 pdf_key_length getinterval
  74. } bind def
  75.  
  76.  
  77. /pdf_padding_string
  78.    <28bf4e5e4e758a41 64004e56fffa0108
  79.     2e2e00b6d0683e80 2f0ca9fe6453697a>
  80. def
  81.  
  82. % Pad a key out to 32 bytes.
  83. /pdf_pad_key {         % <key> pdf_pad_key <padded key>
  84.   dup length 32 gt { 0 32 getinterval } if
  85.   pdf_padding_string
  86.   0 32 3 index length sub getinterval
  87.   concatstrings
  88. } bind def
  89.  
  90. /pdf_xorbytes {      % <iter-num> <key> pdf_xorbytes <xored-key>
  91.   dup length dup string
  92.   exch 1 sub 0 1 3 2 roll {
  93.     % <iter-num> <key> <new-key> <byte-num>
  94.     dup 3 index exch get 4 index xor
  95.     % <iter-num> <key> <new-key> <byte-num> <byte>
  96.     3 copy put pop pop
  97.   } for
  98.   3 1 roll pop pop
  99. } bind def
  100.  
  101. % Get length of encryption key in bytes
  102. /pdf_key_length {    % pdf_key_length <key_length>
  103.   Trailer /Encrypt oget
  104.   dup /V knownoget not { 0 } if 1 eq
  105.   { pop 5 }    % If V == 1 then always use 40 bits
  106.   { /Length knownoget { -3 bitshift } { 5 } ifelse }
  107.   ifelse
  108. } bind def
  109.  
  110. % Algorithm 3.2
  111. /pdf_compute_encryption_key {  % <password> pdf_compute_encryption_key <key>
  112.   % Step 1.
  113.   pdf_pad_key
  114.  
  115.   % Step 2, 3.
  116.   Trailer /Encrypt oget dup /O oget
  117.   % <padded-key> <encrypt> <O>
  118.  
  119.   % Step 4.
  120.   exch /P oget 4 string exch
  121.   2 copy 255 and 0 exch put
  122.   2 copy -8 bitshift 255 and 1 exch put
  123.   2 copy -16 bitshift 255 and 2 exch put
  124.   2 copy -24 bitshift 255 and 3 exch put pop
  125.   % <padded-key> <O> <P>
  126.  
  127.   % Step 5.
  128.   Trailer /ID knownoget { 0 oget } {
  129.     ()
  130.     (   **** ID key in the trailer is required for encrypted files.\n) pdfformaterror
  131.   } ifelse
  132.   3 { concatstrings } repeat 
  133.   % We will finish step 5 after possibly including step 6.
  134.  
  135.   % The following only executed for /R equal to 3 or more
  136.   Trailer /Encrypt oget dup /R oget dup 3 ge {
  137.  
  138.      % Step 6.  If EncryptMetadata is false, pass 0xFFFFFFFF to md5 function
  139.      % The PDF 1.5 Spec says that EncryptMetadata is an undocumented
  140.      % feature of PDF 1.4.  That implies that this piece of logic should
  141.      % be executed if R >= 3.  However testing with Acrobat 5.0 and 6.0 shows
  142.      % that this step is not executed if R equal to 3.  Thus we have a test for
  143.      % R being >= 4.
  144.      4 ge {
  145.        /EncryptMetadata knownoget    % Get EncryptMetadata (if present)
  146.        not { true } if            % Default is true
  147.        not {                % If EncryptMetadata is false
  148.          <ff ff ff ff> concatstrings    % Add 0xFFFFFFFF to working string
  149.        } if
  150.      } {
  151.        pop                % Remove Encrypt dict
  152.      } ifelse
  153.      md5_trunk                % Finish step 5 and 6.
  154.  
  155.      % Step 7.  Executed as part of step 6
  156.      % Step 8.  (This step is defintely a part of PDF 1.4.)
  157.      50 { md5_trunk } repeat
  158.   } {
  159.      pop pop md5_trunk            % Remove R, Encrypt dict, finish step 5
  160.   } ifelse
  161.  
  162.   % Step 9 - Done in md5_trunk.
  163. } bind def
  164.  
  165. % Algorithm 3.4
  166. /pdf_gen_user_password_R2 { % <filekey> pdf_gen_user_password_R2 <U>
  167.  
  168.   % Step 2.
  169.   pdf_padding_string exch arc4decode
  170. } bind def
  171.  
  172. % Algorithm 3.5
  173. /pdf_gen_user_password_R3 { % <filekey> pdf_gen_user_password_R3 <U>
  174.  
  175.   % Step 2.
  176.   pdf_padding_string
  177.  
  178.   % Step 3.
  179.   Trailer /ID knownoget { 0 oget } {
  180.     ()
  181.     (   **** ID key in the trailer is required for encrypted files.\n) pdfformaterror
  182.   } ifelse
  183.   concatstrings md5
  184.  
  185.   % Step 4.
  186.   1 index arc4decode
  187.  
  188.   % Step 5.
  189.   1 1 19 {
  190.     2 index pdf_xorbytes arc4decode
  191.   } for
  192.   exch pop
  193.  
  194. } bind def
  195.  
  196. /pdf_gen_user_password { % <password> pdf_gen_user_password <filekey> <U>
  197.   % common Step 1 of Algorithms 3.4 and 3.5.
  198.   pdf_compute_encryption_key dup
  199.  
  200.   Trailer /Encrypt oget
  201.  
  202.   /R oget dup 2 eq {
  203.     pop pdf_gen_user_password_R2
  204.   } {
  205.     dup 3 eq {
  206.       pop pdf_gen_user_password_R3
  207.     } {
  208.       dup 4 eq {    % 4 uses the algorithm as 3
  209.         pop pdf_gen_user_password_R3
  210.       } {
  211.         (   **** This file uses an unknown standard security handler revision: )
  212.         exch =string cvs concatstrings pdfformaterror printProducer
  213.         /pdf_check_user_password cvx /undefined signalerror
  214.       } ifelse
  215.     } ifelse
  216.   } ifelse
  217. } bind def
  218.  
  219. % Algorithm 3.6
  220. /pdf_check_user_password { % <password> pdf_check_user_password <filekey> true
  221.                            % <password> pdf_check_user_password false
  222.   pdf_gen_user_password
  223.  
  224.   Trailer /Encrypt oget /U oget
  225.  
  226.   0 2 index length getinterval eq {
  227.     true
  228.   } {
  229.     pop false
  230.   } ifelse
  231. } bind def
  232.  
  233. % Compute an owner key, ie the result of step 4 of Algorithm 3.3
  234. /pdf_owner_key % <password> pdf_owner_key <owner-key>
  235. {
  236.   % Step 1.
  237.   pdf_pad_key
  238.  
  239.   % Step 2.
  240.   md5_trunk
  241.  
  242.   % 3.3 Step 3.  Only executed for /R equal to 3 or more
  243.   Trailer /Encrypt oget /R oget 3 ge {
  244.     50 { md5_trunk } repeat
  245.   } if
  246.  
  247.   % Step 4 - Done in md5_trunk.
  248. } bind def
  249.  
  250. % Algorithm 3.7
  251. /pdf_check_owner_password { % <password> pdf_check_owner_password <filekey> true
  252.                             % <password> pdf_check_owner_password false
  253.   % Step 1.
  254.   pdf_owner_key
  255.  
  256.   % Step 2.
  257.   Trailer /Encrypt oget dup /O oget 2 index arc4decode
  258.   % <encryption-key> <encrypt-dict> <decrypted-O>
  259.  
  260.   % Step 3.  Only executed for /R equal to 3 or more
  261.   exch /R oget 3 ge {
  262.     1 1 19 {
  263.       2 index pdf_xorbytes arc4decode
  264.     } for
  265.   } if
  266.   exch pop
  267.   % <result-of-step-3>
  268.  
  269.   pdf_check_user_password
  270. } bind def
  271.  
  272. % Process the encryption information in the Trailer.
  273. /pdf_process_Encrypt {
  274.   Trailer /Encrypt oget
  275.   /Filter oget /Standard eq not {
  276.     (   **** This file uses an unknown security handler.\n) pdfformaterror
  277.     printProducer
  278.     /pdf_process_Encrypt cvx /undefined signalerror
  279.   } if
  280.   () pdf_check_user_password
  281.   {
  282.     /FileKey exch def
  283.   } {
  284.     /PDFPassword where {
  285.        pop PDFPassword pdf_check_user_password
  286.        {
  287.          /FileKey exch def
  288.        } {
  289.          PDFPassword pdf_check_owner_password
  290.          {
  291.            /FileKey exch def
  292.          } {
  293.            (   **** Password did not work.\n) pdfformaterror
  294.        printProducer
  295.        /pdf_process_Encrypt cvx /invalidfileaccess signalerror
  296.          } ifelse
  297.        } ifelse
  298.     } {
  299.       (   **** This file requires a password for access.\n) pdfformaterror
  300.       printProducer
  301.       /pdf_process_Encrypt cvx /invalidfileaccess signalerror
  302.     } ifelse
  303.   } ifelse
  304.  
  305. %   Trailer /Encrypt oget /P oget 4 and 0 eq #? and
  306. %    { (   ****This owner of this file has requested you do not print it.\n)
  307. %      pdfformaterror printProducer
  308. %      /pdf_process_Encrypt cvx /invalidfileaccess signalerror
  309. %    }
  310. %   if
  311. } bind def
  312.  
  313. % Calculate the key used to decrypt an object (to pass to .decpdfrun or
  314. % put into a stream dictionary).
  315. /computeobjkey    % <object#> <generation#> computeobjkey <keystring>
  316. {
  317.   exch
  318.   FileKey length 5 add string
  319.   dup 0 FileKey putinterval
  320.   exch
  321.         % stack:  gen# string obj#
  322.     2 copy 255 and FileKey length exch put
  323.     2 copy -8 bitshift 255 and FileKey length 1 add exch put
  324.     2 copy -16 bitshift 255 and FileKey length 2 add exch put
  325.   pop exch
  326.     2 copy 255 and FileKey length 3 add exch put
  327.     2 copy -8 bitshift 255 and FileKey length 4 add exch put
  328.   pop
  329.     % this step is for the AES cipher only
  330.     Trailer /Encrypt oget
  331.     dup /StmF known
  332.      {
  333.       dup /StmF oget
  334.       exch /CF oget exch oget /CFM oget
  335.       /AESV2 eq {
  336.         (sAlT) concatstrings
  337.       } if
  338.      }
  339.      { pop }
  340.     ifelse
  341.   md5 0 FileKey length 5 add 2 index length .min getinterval
  342. } bind def
  343.  
  344. % As .pdfrun, but decrypt strings with key <key>.
  345. /PDFScanRules_true << /PDFScanRules true >> def
  346. /PDFScanRules_null << /PDFScanRules null >> def
  347. /.decpdfrun            % <file> <keystring> <opdict> .decpdfrun -
  348.  {     % Construct a procedure with the file, opdict and key bound into it.
  349.    2 index cvlit mark
  350.    /PDFScanRules .getuserparam //null eq {
  351.      //PDFScanRules_true { setuserparams } 0 get % force PDF scanning mode
  352.      mark 7 4 roll
  353.    } {
  354.      mark 5 2 roll
  355.    } ifelse
  356.     { .pdftoken not { (%%EOF) cvn cvx } if
  357.       dup xcheck
  358.        { PDFDEBUG { dup == flush } if
  359.      3 -1 roll pop
  360.      2 copy .knownget
  361.       { exch pop exch pop exec
  362.           }
  363.       { exch pop
  364.             dup /true eq
  365.               { pop //true
  366.               }
  367.               { dup /false eq
  368.                   { pop //false 
  369.                   }
  370.                   { dup /null eq
  371.                       { pop //null
  372.                       }
  373.                       { (   **** Unknown operator: ) 
  374.                     exch =string cvs concatstrings (\n) concatstrings
  375.             pdfformaterror
  376.                       }
  377.                     ifelse
  378.                   }
  379.                 ifelse
  380.               }
  381.             ifelse
  382.       }
  383.      ifelse
  384.        }
  385.        { exch pop PDFDEBUG { dup ==only ( ) print flush } if
  386.      dup type /stringtype eq
  387.           {
  388.     % Check if we have encrypted strings R=4 allows for
  389.     % selection of encryption on streams and strings
  390.             Trailer /Encrypt oget    % Get encryption dictionary
  391.             dup /R oget 4 lt        % only 4 has selectable
  392.              {                % R < 4 --> arc4 strings
  393.            pop 1 index arc4decode    % Decrypt string
  394.            PDFDEBUG { (%Decrypted: ) print dup == flush } if
  395.              } {            % Else R = 4
  396.            /StrF knownoget        % Get StrF (if present)
  397.             {            % If StrF is present ...
  398.           dup /Identity eq not    % Check if StrF != Identity
  399.              { /StdCF eq
  400.                { Trailer /Encryption oget /StdCF oget /CFM oget
  401.              /AESV2 eq
  402.                % Decrypt string
  403.                { 1 index aesdecode }
  404.                { 1 index arc4decode }
  405.              ifelse
  406.                }
  407.                { 1 index arc4decode }
  408.              ifelse        % If StrF != StdCF
  409.              PDFDEBUG { (%Decrypted: ) print dup == flush } if
  410.            }
  411.            { pop }
  412.           ifelse        % If StrF != identity
  413.         }
  414.            if            % If StrF is known
  415.                }
  416.         ifelse            % Ifelse R < 4
  417.       }
  418.      if                % If = stringtype
  419.      exch pop
  420.        }
  421.       ifelse
  422.     }
  423.    aload pop .packtomark cvx
  424.    { loop } 0 get 2 packedarray cvx
  425.     { stopped } 0 get
  426.    /PDFScanRules .getuserparam //null eq {
  427.      //PDFScanRules_null { setuserparams } 0 get % reset PDF scannig mode if it was off
  428.    } if
  429.    /PDFsource PDFsource
  430.     { store { stop } if } aload pop .packtomark cvx 
  431.    /PDFsource 3 -1 roll store exec
  432.  } bind def
  433. currentdict /PDFScanRules_true undef
  434. currentdict /PDFScanRules_null undef
  435.  
  436. % Run the code to resolve an object reference.
  437. /pdf_run_resolve
  438. { /FileKey where            % Check if the file is encrypted
  439.   { pop                    % File is encrypted
  440.     2 copy computeobjkey dup 4 1 roll
  441.     PDFfile exch resolveopdict .decpdfrun
  442.     dup dup dup 5 2 roll
  443.     % stack: object object key object object
  444.     {    % Use loop to provide an exitable context.
  445.       xcheck exch type /dicttype eq and % Check if executable dictionary
  446.       not {                % If object is not ...
  447.         pop pop                % ignore object
  448.         exit                % Exit 'loop' context
  449.       } if                % If not possible stream
  450.     % Starting with PDF 1.4 (R = 3), there are some extra features
  451.     % which control encryption of streams.  The EncryptMetadata entry
  452.     % in the Encrypt dict controls the encryption of metadata streams.
  453.       Trailer /Encrypt oget        % Get encryption dictionary
  454.       dup /R oget dup 3 lt        % Only PDF 1.4 and higher has options
  455.       {                    % R < 3 --> all streams encrypted
  456.         pop pop /StreamKey exch put    % Insert StreamKey in dictionary
  457.     exit                % Exit 'loop' context
  458.       } if
  459.     % Check EncryptMeta.  stack: object object key Encrypt R
  460.       exch dup /EncryptMetadata knownoget % Get EncryptMetadata (if present)
  461.       not { true } if            % If not present default = true
  462.       not                % Check if EncryptMetadata = false
  463.       {                    % if false we need to check the stream type
  464.     3 index /Type knownoget        % Get stream type (if present)
  465.     not { //null } if        % If type not present use fake name
  466.     /Metadata eq            % Check if the type is Metadata
  467.         { pop pop pop pop        % Type == Metadata --> no encryption
  468.       exit                % Exit 'loop' context
  469.         } if
  470.       } if
  471.         % PDF 1.5 encryption (R == 4) has selectable encryption handlers.  If
  472.     % this is not PDF 1.5 encryption (R < 4) then we are done checking and
  473.     % we need to decrypt the stream.  stack: object object key R Encrypt
  474.       exch 4 lt                % Check for less than PDF 1.5
  475.       { pop /StreamKey exch put        % Insert StreamKey in dictionary
  476.     exit                % Exit 'loop' context
  477.       } if
  478.     % Check if the stream encryption handler (StmF) == Identity.
  479.       PDFDEBUG {
  480.     Trailer /Encrypt oget /CF get /StdCF get /CFM get
  481.     (Encrypt StmF is StdCF with CFM ) print =
  482.       } if
  483.       /StmF knownoget            % Get StmF (if present)
  484.       not { /Identity } if        % If StmF not present default = Identity
  485.       /Identity eq            % Check if StmF == Identity
  486.       { pop pop                % Identity --> no encryption
  487.     exit                % Exit 'loop' context
  488.       } if
  489.           % If we get here then we need to decrypt the stream.
  490.       /StreamKey exch put        % Insert StreamKey into dictionary
  491.       exit                % Exit 'loop' context, never loop
  492.     } loop                % End of loop exitable context
  493.   } {                    % Else file is not encrypted
  494.     PDFfile resolveopdict .pdfrun
  495.   } ifelse                % Ifelse encrypted
  496. } bind def
  497.  
  498. % Prefix a decryption filter to a stream if needed.
  499. % Stack: readdata? dict parms file/string filternames
  500. % (both before and after).
  501. /pdf_decrypt_stream
  502.  { 3 index /StreamKey known    % Check if the file is encrypted
  503.    {
  504.       exch 
  505.     % Stack: readdata? dict parms filternames file/string
  506.       3 index /StreamKey get
  507.       Trailer /Encrypt oget dup /StmF 
  508.       known
  509.        {
  510.     dup /StmF oget        % stack: key Encrypt StmF
  511.     exch /CF oget
  512.     exch oget /CFM oget    % stack: key StmF-CFM
  513.     /AESV2 eq
  514.      { aesdecodefilter }    % install the requested filter
  515.      { arc4decodefilter }
  516.     ifelse
  517.        } 
  518.        { pop arc4decodefilter }    % fallback for no StmF
  519.       ifelse
  520.       exch
  521.    } if
  522.  } bind def
  523.  
  524. end            % pdfdict
  525. .setglobal
  526.